package gazzera.node.core.plugins;

import gazzera.gui.*;
import gazzera.gui.messages.*;
import gazzera.node.core.*;
import gazzera.node.core.messages.*;
import gazzera.node.core.peer.*;
import gazzera.node.core.plugins.shareplugin.*;
import gazzera.utils.*;

import java.util.*;


public class PeopleManagerPlugin implements Plugin
{

	private ICore core = null;
	
	@Override
	public void dataPumpTerminated(Node node, DataPumpSource src)
	{
		
	}

	@Override
	public void taskTerminated(Task task, boolean interrupted) throws Exception
	{
	
	}

	@Override
	public void finish() throws Exception
	{
	
	}

	@Override
	public void command(GuiMessage msg) throws Exception
	{
		GuiInterface gui = core.getGui();
		
		if(msg instanceof Status)
		{
			Collection<Person> p = core.getPeoples().getAll();
			for (Person person : p)
			{
				updatePerson(gui, person);
			}
		}
		else if (msg instanceof ConnectUrl)
		{
			core.connect(((ConnectUrl) msg).host, ((ConnectUrl) msg).port, null);
		}
		else if (msg instanceof ConnectNode)
		{
			String hash = ((ConnectNode) msg).hash;
			connectNode(hash);
		}
		else if (msg instanceof AddFriend)
		{
			addFriendCommand((AddFriend)msg, core.getPeoples());			
		}
		else if (msg instanceof RemoveFriend)
		{
			removeFriendCommand((RemoveFriend)msg, core.getPeoples());			
		}
		else if(msg instanceof ChangeNodeGroups)
		{
			changeNodeGroups((ChangeNodeGroups)msg);
		}
	}


	private void changeNodeGroups(ChangeNodeGroups msg) throws Exception
	{
		Person p = core.getPeoples().get(msg.hash);
		if(p == null)
		{
			core.getGui().pass(new Log("Unknown hash"));
		}
		p.groups = msg.groups;
		core.getPeoples().save();
		updatePerson(core.getGui(), p);
	}

	private void connectNode(String hash)
	{
		Node node = core.find(hash);
		if (node != null)
		{
			core.getGui().pass(new Log("Already online"));
			return;
		}
		
		Person p = core.getPeoples().get(hash);
		if(p == null)
		{
			core.getGui().pass(new Log("Unknown hash"));
		}
		else if(p.onlineStatus != OnlineStatus.OFFLINE)
		{
			core.getGui().pass(new Log("Already online or connecting"));
		}
		else if((p.status != FriendStatus.FRIEND) && (p.status != FriendStatus.TRUSTED))
		{
			core.getGui().pass(new Log("Not friend, will not connect"));
		}
		else if( (p.host == null) || p.host.equals(""))
		{
			core.getGui().pass(new Log("Peer address unknown"));
		}
		else
		{
			core.connect(p.host, p.port, p);
		}
	}

	public static void updatePerson(GuiInterface gui, Person p)
	{
		PersonUpdate msg = new PersonUpdate(p.hash, p.nickname, p.status, p.port, p.host, p.onlineStatus, p.groups);
		gui.pass(msg);
	}
	
	private void removeFriendCommand(RemoveFriend m, Peoples ps) throws Exception
	{
		String hash;
		String[] tokens = RegExp.group(m.gid);
		if (tokens == null)
		{
			hash = m.gid;
		}
		else
		{
			hash = tokens[2];
		}
		// disconnect if connected
		Node n = core.find(hash);
		if(n!=null)
		{
			n.close();
		}
		
		Person p = ps.get(hash);
		if (p != null)
		{
			p.status = FriendStatus.STRANGER;
			ps.save();
			updatePerson(core.getGui(), p);
		}
		else
		{
			core.getGui().pass(new Log("Friend not found"));

		}
	}
	private void addFriendCommand(AddFriend m, Peoples ps) throws Exception
	{
		String[] tokens = RegExp.group(m.gid);
		if (tokens == null)
		{
			core.getGui().pass(new Log("Invalid gid"));
			return;
		}
		String hash = tokens[2];
		
		Person p = ps.get(hash);
		if (p != null)
		{
			// if it's already friend, give error.
			// if it's known but stranger, add as friend and send an update
		    if (p.status != FriendStatus.FRIEND)
		    {
		    	p.nickname = tokens[1];
		    	p.status = FriendStatus.FRIEND;
				if ((tokens.length >= 5) && (!Str.isEmpty(tokens[5])))
				{
				    p.port = Integer.parseInt(tokens[5]);
				    p.host = tokens[4];    
				}
				ps.save();
				
				updatePerson(core.getGui(), p);
				core.getGui().pass(new Log("Friend added :)"));
				
				if ((p.host!=null) && (core.find(hash)==null) ) 
				{
					core.connect(p.host, p.port, p);
				}
		    }
		    else
		    {
		    	core.getGui().pass(new Log("Already friend"));
		    }
		}
		else
		{
			p = new Person();
			p.hash = hash;
			p.onlineStatus = OnlineStatus.OFFLINE;
			p.nickname = tokens[1];
			p.status = FriendStatus.FRIEND;
			if (tokens[5] != null)
			{
			    p.port = Integer.parseInt(tokens[5]);
			    p.host = tokens[4];    
			}
			else
			{
				p.host = null;
				p.port = 0;
			}
			
			ps.add(p);
			ps.save();

			updatePerson(core.getGui(), p);
			core.getGui().pass(new Log("Friend added :)"));
			
			if ((p.host!=null) && (core.find(hash)==null) )
			{
				core.connect(p.host, p.port, p);
			}
		}
	}
	@Override
	public void init(ICore core) throws Exception
	{
		this.core = core;
		
	}
	public void start() throws Exception
	{
		Collection<Person> px = core.getPeoples().getAll();
		for (Person p : px)
		{
			if( (p.onlineStatus == OnlineStatus.OFFLINE) &&
					( (p.status == FriendStatus.FRIEND) || (p.status == FriendStatus.TRUSTED) ) && 
					(!Str.isEmpty(p.host)) &&
					(p.port!=0) )
			{
				core.connect(p.host, p.port, p);
			}
		}
		
		Set<String> allGroups = new HashSet<String>();
		Collection<Person> x = core.getPeoples().getAll();
		for (Person p : x)
		{
			allGroups.addAll(p.groups);
		}
		SharePlugin sp = core.getPlugin(SharePlugin.class);
		for (Share s : sp.getShares().values())
		{
			allGroups.addAll(s.getGroups());
		}
		//System.out.println(allGroups);
		if (allGroups.size() == 0)
		{
			allGroups.add("Family");
			allGroups.add("Friends");
			allGroups.add("Coworker");
		}
		core.getGui().pass(new AllCurrentGroups(allGroups));
	}

	@Override
	public void message(Node node, Message msg) throws Exception
	{
		if( msg instanceof Hello)
		{
			Hello h = (Hello) msg;
			if(h.majorVersion != Core.MAJOR_VERSION)
			{
				if(h.majorVersion > Core.MAJOR_VERSION)
				{
					core.getGui().pass(new Log("Node "+node.getHash()+" runs a newer, incompatible version of Gazzera."));
				}
				node.close();
			}
			else
			{
				Person p = core.getPeoples().get(node.getHash());
				p.nickname = h.nickname;
				p.port = h.port;
				if(!Str.isEmpty(h.dynhost))
				{
					p.host = h.dynhost;
				}
				core.getPeoples().save();
				updatePerson(core.getGui(), p);
			}
		}

	}

	@Override
	public void nodeConnected(Node node)
	{
		Person us = core.getOurPerson();
		Hello hello = new Hello(Core.MAJOR_VERSION,Core.MINOR_VERSION,us.hash, us.nickname, us.port, core.getConfig().get("dynamic.host"), null, null );
		node.enqueue(hello);
	}

	@Override
	public void nodeDisconnected(Node node)
	{
		

	}
	

}
